from flask import abort, jsonify
from flask import current_app
from flask import g
from flask import request
from flask import session
from info import constants, db
from info.models import User, News, Comment, CommentLike
from info.utlis.response_code import RET
from . import news_bp
from flask import render_template
from info.utlis.common import login_user_data


@news_bp.route('/followed_user', methods=['POST'])
@login_user_data
def followed_user():
    """关注 取消关注"""

    #1获取参数
    user_id = request.json.get("user_id")
    action = request.json.get("action")
    user = g.user

    #  2.1 非空判断
    if not all([user_id, action]):
        return jsonify(errno=RET.PARAMERR, errmsg="参数不足")

    # 2.2 用户是否登录判断
    if not user:
        return jsonify(errno=RET.SESSIONERR, errmsg="用户未登录")

    if action not in ["follow", "unfollow"]:
        return jsonify(errno=RET.PARAMERR, errmsg="action参数错误")

    # 3.逻辑处理
    try:
        author = User.query.get(user_id)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg="查询作者异常")
    if not author:
        return jsonify(errno=RET.NODATA, errmsg="作者不存在")

    if action == "follow":
        # 关注
        # 作者没有在当前用户的偶像列表（当前用户没有关注作者）
        if author not in user.followed:
            user.followed.append(author)
        else:
            return jsonify(errno=RET.DATAEXIST, errmsg="用户已经关注改作者")
    else:
        # 作者在当前用户的偶像列表
        if author in user.followed:
            # 取消关注
            user.followed.remove(author)

    try:
        db.session.commit()
    except Exception as e:
        current_app.logger.error(e)
        db.session.rollback()
        return jsonify(errno=RET.DBERR, errmsg="用户保存到数据库异常")

    return jsonify(errno=RET.OK, errmsg="OK")


@news_bp.route('/comment_like', methods=["POST"])
@login_user_data
def comment_like():
    """评论的点赞、取消点赞"""
    """
    1.获取参数
        1.1 用户对象 新闻id 评论id action(点赞、取消点赞)
    2.校验参数
        2.1 非空判断
        2.2 用户是否登录判断
        2.3 action in ["add", "remove"]
    3.逻辑处理
        3.1 根据评论id获取评论模型对象（只有评论存在的时候你才能去点赞、取消点赞）
        3.2 跟action去完成点赞或者取消点赞的功能
        3.3 点赞： 根据 user_id和comment_id 查询CommentLike是否存在
            3.3.1 CommentLike存在：表示用户点过这条评论
            3.3.2 CommentLike不存在：新建CommentLike模型对象最终保存回数据库
            3.3.3 记录comment模型的点赞数量（+1）
        3.4 取消点赞：根据 user_id和comment_id 查询CommentLike是否存在
            CommentLike存在才取消点赞
            记录comment模型的点赞数量（-1）

    4.返回值处理
    """
    # 1.1 用户对象 新闻id 评论id action(点赞、取消点赞)
    params_dict = request.json
    news_id = params_dict.get("news_id")
    comment_id = params_dict.get("comment_id")
    action = params_dict.get("action")
    user = g.user

    #  2.1 非空判断
    if not all([news_id, comment_id, action]):
        return jsonify(errno=RET.PARAMERR, errmsg="参数不足")

    # 2.2 用户是否登录判断
    if not user:
        return jsonify(errno=RET.SESSIONERR, errmsg="用户未登录")

    if action not in ["add", "remove"]:
        return jsonify(errno=RET.PARAMERR, errmsg="action数据填写错误")

    #3.1 根据评论id获取评论模型对象（只有评论存在的时候你才能去点赞、取消点赞）
    try:
        comment = Comment.query.get(comment_id)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg="查询评论数据异常")

    if not comment:
        return jsonify(errno=RET.NODATA, errmsg="评论不存在")

    #3.2 跟action去完成点赞或者取消点赞的功能
    if action == "add":
        #3.3 点赞： 根据 user_id和comment_id 查询CommentLike是否存在
        #3.3.1 CommentLike存在：表示用户点过这条评论
        comment_like = CommentLike.query.filter(CommentLike.user_id == user.id,
                                 CommentLike.comment_id == comment_id
                                 ).first()
        if not comment_like:
            #3.3.2 CommentLike不存在：新建CommentLike模型对象最终保存回数据库
            comment_like = CommentLike()
            comment_like.user_id = user.id
            comment_like.comment_id = comment_id
            db.session.add(comment_like)
            #3.3.3 记录comment模型的点赞数量（+1）
            comment.like_count += 1
    else:
        #3.4 取消点赞：根据 user_id和comment_id 查询CommentLike是否存在
        # 只有comment_like对象存在的时候才能去取消点赞
        comment_like = CommentLike.query.filter(CommentLike.user_id == user.id,
                                                CommentLike.comment_id == comment_id
                                                ).first()
        #CommentLike存在才取消点赞
        if comment_like:
            # 删除数据库数据
            db.session.delete(comment_like)
            #记录comment模型的点赞数量（-1）
            comment.like_count -= 1

    # 将上述对于数据库模型对象的修改提交到数据库
    try:
        db.session.commit()
    except Exception as e:
        current_app.logger.error(e)
        db.session.rollback()
        return jsonify(errno=RET.DBERR, errmsg="保存数据异常")

    #4. 组织响应对象
    return jsonify(errno=RET.OK, errmsg="OK")


@news_bp.route('/news_comment', methods=["POST"])
@login_user_data
def news_comment():
    """评论接口（主评论 子评论）"""
    """
        1.获取参数
            1.1 用户对象 新闻id 评论内容 parent_id(主评论id)
        2.校验参数
            2.1 非空判断
            2.2 用户是否登录判断
        3.逻辑处理
            3.1 根据新闻id查询该新闻（新闻存在才能去评论）
            3.2 创建评论模型 给各个属性赋值
            3.3 判断parent_id是否有值
            3.4 将模型对象保存到数据库
        4.返回值处理
        """
    # 1.1 用户对象 新闻id 评论内容 parent_id(主评论id)
    params_dict = request.json
    news_id = params_dict.get("news_id")
    comment = params_dict.get("comment")
    parent_id = params_dict.get("parent_id")
    user = g.user

    #  2.1 非空判断
    if not all([news_id, comment]):
        return jsonify(errno=RET.PARAMERR, errmsg="参数不足")

    #  2.2 用户是否登录判断
    if not user:
        return jsonify(errno=RET.SESSIONERR, errmsg="用户未登录")

    #3.1 根据新闻id查询该新闻（新闻存在才能去评论）
    try:
        news = News.query.get(news_id)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg="查询新闻对象异常")
    if not news:
        return jsonify(errno=RET.NODATA, errmsg="新闻不存在")

    #3.2 创建评论模型 给各个属性赋值
    comment_obj = Comment()
    comment_obj.user_id = user.id
    comment_obj.news_id = news_id
    comment_obj.content = comment
    #3.3 判断parent_id是否有值
    if parent_id:
        # parent_id有值表示是子评论
        comment_obj.parent_id = parent_id

    #3.4 将模型对象保存到数据库
    try:
        db.session.add(comment_obj)
        db.session.commit()
    except Exception as e:
        current_app.logger.error(e)
        db.session.rollback()
        return jsonify(errno=RET.DBERR, errmsg="保存评论对象到数据库异常")

    # 4.组织响应对象
    return jsonify(errno=RET.OK, errmsg="评论成功", data=comment_obj.to_dict())


# 127.0.0.1:5000/news/news_collect  POST
@news_bp.route('/news_collect', methods=["POST"])
@login_user_data
def news_collect():
    """收藏和取消收藏接口"""
    """
    1.获取参数
        1.1 用户对象 新闻id action：（收藏or取消收藏）
    2.校验参数
        2.1 非空判断
        2.2 用户是否登录判断
        2.3 action值的判断 action in ["collect", "cancel_collect"]
    3.逻辑处理
        3.1 根据新闻id查询该新闻
        3.2 取消收藏：将新闻对象从collection_news列表中移除
        3.3 收藏： 将新闻添加到collection_news中
        3.4 提交修改操作到数据库
    4.返回值处理
    """
    #1.1 用户对象 新闻id action：（收藏or取消收藏）
    params_dict = request.json
    news_id = params_dict.get("news_id")
    action = params_dict.get("action")
    user = g.user

    # 2.1 非空判断
    if not all([news_id, action]):
        return jsonify(errno=RET.PARAMERR, errmsg="参数不足")

    # 2.2 用户是否登录判断
    if not user:
        return jsonify(errno=RET.SESSIONERR, errmsg="用户未登录")

    # 2.3 action值的判断 action in ["collect", "cancel_collect"]
    if action not in ["collect", "cancel_collect"]:
        return jsonify(errno=RET.PARAMERR, errmsg="参数填写错误")

    #3.1 根据新闻id查询该新闻
    news = None
    try:
        news = News.query.get(news_id)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg="查询新闻数据异常")
    if not news:
        return jsonify(errno=RET.NODATA, errmsg="新闻不存在")

    # 3 收藏
    if action == "collect":
        # 3.2 收藏： 将新闻添加到collection_news中
        user.collection_news.append(news)
    else:
        #3.3 取消收藏：将新闻对象从collection_news列表中移除
        user.collection_news.remove(news)

    #3.4 提交修改操作到数据库
    try:
        db.session.commit()
    except Exception as e:
        current_app.logger.error(e)
        # 回滚
        db.session.rollback()
        return jsonify(errno=RET.DBERR, errmsg="提交数据到数据库异常")

    #4.组织响应数据
    return jsonify(errno=RET.OK, errmsg="OK")


# 127.0.0.1:5000/news/2
@news_bp.route('/<int:news_id>')
@login_user_data
def news_detail(news_id):
    """新闻详情首页"""

    # -------1.当用户登录成功后可以使用session对象获取里面的用户user_id -------
    user = g.user
    # # 1. 获取user_id
    # user_id = session.get("user_id")
    # # 2. 根据user_id查询用户对象
    # user = None  # type: User
    # try:
    #     if user_id:
    #         user = User.query.get(user_id)
    #         # 3. 将用户对象转成python的字典对象
    #         # if user:
    #         #     return user.to_dict()
    #         # else:
    #         #     return None
    # except Exception as e:
    #     current_app.logger.error(e)

    # -------2.查询新闻的点击排行数据 -------
    # 1.根据浏览量查询6条点击排行的新闻数据
    # [news1, news2,....] news属于News的对象
    try:
        news_model_list = News.query.order_by(News.clicks.desc()).limit(constants.CLICK_RANK_MAX_NEWS)
    except Exception as e:
        current_app.logger.error(e)
        # 切记不能返回return 否则首页都渲染不了啦，只需要返回一个None的数据即可

    # 2. 将模型列表转换成字典列表
    news_dict_list = []
    for news in news_model_list if news_model_list else None:
        # 获取到new对象调用to_dict方法将对象转换成字典，再添加到news_dict_list中
        news_dict_list.append(news.to_dict())

    # -------3.查询新闻的详情数据 -------
    try:
        news = News.query.get(news_id)
    except Exception as e:
        current_app.logger.error(e)

    if not news:
        abort(404)
    # 浏览量自增
    news.clicks += 1

    # 将模型的修改提交到数据库
    try:
        db.session.commit()
    except Exception as e:
        current_app.logger.error(e)
        db.session.rollback()
        abort(404)

    # -------4.查询用户是否收藏过该新闻 -------
    # True: 用户收藏过该条新闻 False:用户未收藏该新闻
    is_collected = False
    # False 当前登录用户未关注该新闻的作者 反之
    is_followed = False

    if user:
        if news in user.collection_news:
            # news在用户收藏的新闻列表内 表示用户收藏过该新闻，is_collected修改成True
            is_collected = True
    # user: 当前登录用户
    # news.user: 新闻的作者
    # 用户登录&作者存在的情况
    if user and news.user:

        # 当前作者在用户的偶像列表内(关注了)
        # if news.user in user.followed

        # 当前用户是作者的粉丝（关注了）
        if user in news.user.followers:
            is_followed = True
    #  -------5.查询该新闻的评论数据 -------
    try:
        comments = Comment.query.filter(Comment.news_id == news_id).order_by(Comment.create_time.desc()).all()
    except Exception as e:
        current_app.logger.error(e)

    # -------6.需求：查询当前用户在当前新闻的评论里边具体点赞了那几条评论 -------
    commentlike_id_list = []
    if user:
        # 1. 查询出当前新闻的所有评论，取得所有评论的id —>  list[1,2,3,4,5,6]
        comment_id_list = [comment.id for comment in comments]

        # 2.再通过评论点赞模型(CommentLike)查询当前用户点赞了那几条评论  —>[模型1,模型2...]
        commentlike_model_list = CommentLike.query.filter(CommentLike.comment_id.in_(comment_id_list),
                                 CommentLike.user_id == user.id
                                 ).all()

        # 3. comment_like.comment_id通过上一步的模型列表，获取所以点赞过的评论id
        commentlike_id_list = [commentlike.comment_id for commentlike in commentlike_model_list]

    # 模型列表转字典列表
    comment_dict_list = []
    for comment in comments if comments else []:
        comment_dict = comment.to_dict()
        # 评论点赞的标志位
        comment_dict["is_like"] = False
        # 1 2 3 4 5  in  [1,3,5]
        if comment.id in commentlike_id_list:
            comment_dict["is_like"] = True

        comment_dict_list.append(comment_dict)

    # --------
    data = {
        "user_info": user.to_dict() if user else None,
        "newsClicksList": news_dict_list,
        "news": news.to_dict(),
        "is_collected": is_collected,
        "is_followed": is_followed,
        "comments": comment_dict_list
    }

    return render_template("news/detail.html", data=data)

